#pragma once

#include "Socket.h"
#include <functional>
#include <sys/types.h>
#include <sys/wait.h>

namespace zmh
{
    // 服务器一般是不可拷贝的,甚至有些环境下应该是单例模式
    // 服务器只负责获取链接 关闭链接的操作 协议模块负责数据的收发与格式化
    class serve : public nocopy
    {
        typedef std::function<void(std::shared_ptr<Socket>)> service;

    public:
        serve(const Intaddr &addr, const service &func, int backlog = 16)
            : _listSocket(std::make_shared<Tcp_Socket>()),
              _addr(addr),
              _func(func),
              _isrunning(false)
        {
            _listSocket->GetListenSocket(_addr, backlog);
        }
        void start()
        {
            _isrunning = true;
            while (_isrunning)
            {
                Intaddr peer;
                std::shared_ptr<Socket> serveSocket = _listSocket->accept(peer);
                if (serveSocket == nullptr)
                    continue;

                pid_t pid = fork();
                if (pid < 0)
                {
                    LOG(FATAL) << "fork mistake: " << strerror(errno);
                    exit(Err_Fork);
                }
                else if (pid == 0)
                {
                    // 子进程
                    // 关闭不需要的监听套接字
                    _listSocket->close();
                    _func(serveSocket);
                    exit(0);
                }
                else
                {
                    // 父进程
                    // 关闭不需要的连接套接字
                    serveSocket->close();
                    // 不需要等待啦,SIG_CHID信号已经默认了
                    // if (waitpid(pid, nullptr, 0) == -1)
                    // {
                    //     LOG(WARNING) << "waitpid mistake: " << strerror(errno);
                    //     continue;
                    // }
                    // LOG(INFO) << "waitpid sucess, 进程ID: " << pid;
                }
            }
            _isrunning = false;
        }

    private:
        std::shared_ptr<Socket> _listSocket; // 监听套接字
        Intaddr _addr;                       // socket
        service _func;                       // 回调函数 --- 提供某种服务
        bool _isrunning;                     // 服务器的状态 --- true表运行
    };
}
